#include "FastIO.h"

#include "Init.h"

#define VALID_FAST_IO_DISPATCH_HANDLER(FastIoDispatchPtr, FieldName)    \
    (((FastIoDispatchPtr) != NULL) &&                                   \
    (((FastIoDispatchPtr)->SizeOfFastIoDispatch) >=                     \
    (FIELD_OFFSET(FAST_IO_DISPATCH, FieldName) + sizeof(PVOID))) &&     \
    ((FastIoDispatchPtr)->FieldName != NULL))

#pragma alloc_text(PAGE, FastIOCheckIfPossible)

BOOLEAN FastIOCheckIfPossible(IN PFILE_OBJECT pFileObject,
                              IN PLARGE_INTEGER pliFileOffset,
                              IN ULONG ulLength,
                              IN BOOLEAN bWait,
                              IN ULONG ulLockKey,
                              IN BOOLEAN bCheckForReadOperation,
                              OUT PIO_STATUS_BLOCK pIOStatus,
                              IN PDEVICE_OBJECT pDeviceObject)
{
    PAGED_CODE();

    // continue Fast I/O processing if attached to this device
    if (NULL != pDeviceObject->DeviceExtension)
    {
        PFILE_HIDING_FILTER_DEVICE_EXTENSION pFilterDeviceExt = (PFILE_HIDING_FILTER_DEVICE_EXTENSION)pDeviceObject->DeviceExtension;
        PFAST_IO_DISPATCH pFastIODispatch = NULL;        

        ASSERT(IS_FILE_HIDING_FILTER_OBJECT(pDeviceObject));
        ASSERT(NULL != pFilterDeviceExt->pNextLowerDevice);

        pFastIODispatch = pFilterDeviceExt->pNextLowerDevice->DriverObject->FastIoDispatch;

        // check Fast I/O handler validation on the next device
        if (VALID_FAST_IO_DISPATCH_HANDLER(pFastIODispatch, FastIoCheckIfPossible))
        {
            // send Fast I/O to the next device
            return pFastIODispatch->FastIoCheckIfPossible(pFileObject,
                                                          pliFileOffset,
                                                          ulLength,
                                                          bWait,
                                                          ulLockKey,
                                                          bCheckForReadOperation,
                                                          pIOStatus,
                                                          pFilterDeviceExt->pNextLowerDevice);
        }
    }

    return FALSE;
}

#pragma alloc_text(PAGE, FastIORead)

BOOLEAN FastIORead(IN PFILE_OBJECT pFileObject,
                   IN PLARGE_INTEGER pliFileOffset,
                   IN ULONG ulLength,
                   IN BOOLEAN bWait,
                   IN ULONG ulLockKey,
                   OUT PVOID pBuffer,
                   IN OUT PIO_STATUS_BLOCK pIOStatus,
                   IN PDEVICE_OBJECT pDeviceObject)
{
    PAGED_CODE();

    // continue Fast I/O processing if attached to this device
    if (NULL != pDeviceObject->DeviceExtension)
    {
        PFILE_HIDING_FILTER_DEVICE_EXTENSION pFilterDeviceExt = (PFILE_HIDING_FILTER_DEVICE_EXTENSION)pDeviceObject->DeviceExtension;
        PFAST_IO_DISPATCH pFastIODispatch = NULL;        

        ASSERT(IS_FILE_HIDING_FILTER_OBJECT(pDeviceObject));
        ASSERT(NULL != pFilterDeviceExt->pNextLowerDevice);

        pFastIODispatch = pFilterDeviceExt->pNextLowerDevice->DriverObject->FastIoDispatch;

        // check Fast I/O handler validation on the next device
        if (VALID_FAST_IO_DISPATCH_HANDLER(pFastIODispatch, FastIoRead))
        {
            // send Fast I/O to the next device
            return pFastIODispatch->FastIoRead(pFileObject,
                                               pliFileOffset,
                                               ulLength,
                                               bWait,
                                               ulLockKey,
                                               pBuffer,
                                               pIOStatus,
                                               pFilterDeviceExt->pNextLowerDevice);
        }
    }

    return FALSE;
}

#pragma alloc_text(PAGE, FastIOWrite)

BOOLEAN FastIOWrite(IN PFILE_OBJECT pFileObject,
                    IN PLARGE_INTEGER pliFileOffset,
                    IN ULONG ulLength,
                    IN BOOLEAN bWait,
                    IN ULONG ulLockKey,
                    IN PVOID pBuffer,
                    IN OUT PIO_STATUS_BLOCK pIOStatus,
                    IN PDEVICE_OBJECT pDeviceObject)
{
    PAGED_CODE();

    // continue Fast I/O processing if attached to this device
    if (NULL != pDeviceObject->DeviceExtension)
    {
        PFILE_HIDING_FILTER_DEVICE_EXTENSION pFilterDeviceExt = (PFILE_HIDING_FILTER_DEVICE_EXTENSION)pDeviceObject->DeviceExtension;
        PFAST_IO_DISPATCH pFastIODispatch = NULL;        

        ASSERT(IS_FILE_HIDING_FILTER_OBJECT(pDeviceObject));
        ASSERT(NULL != pFilterDeviceExt->pNextLowerDevice);

        pFastIODispatch = pFilterDeviceExt->pNextLowerDevice->DriverObject->FastIoDispatch;

        // check Fast I/O handler validation on the next device
        if (VALID_FAST_IO_DISPATCH_HANDLER(pFastIODispatch, FastIoWrite))
        {
            // send Fast I/O to the next device
            return pFastIODispatch->FastIoWrite(pFileObject,
                                                pliFileOffset,
                                                ulLength,
                                                bWait,
                                                ulLockKey,
                                                pBuffer,
                                                pIOStatus,
                                                pFilterDeviceExt->pNextLowerDevice);
        }
    }

    return FALSE;
}

#pragma alloc_text(PAGE, FastIOQueryBasicInfo)

BOOLEAN FastIOQueryBasicInfo(IN PFILE_OBJECT pFileObject,
                             IN BOOLEAN bWait,
                             OUT PFILE_BASIC_INFORMATION pBuffer,
                             OUT PIO_STATUS_BLOCK pIOStatus,
                             IN PDEVICE_OBJECT pDeviceObject)
{
    PAGED_CODE();

    // continue Fast I/O processing if attached to this device
    if (NULL != pDeviceObject->DeviceExtension)
    {
        PFILE_HIDING_FILTER_DEVICE_EXTENSION pFilterDeviceExt = (PFILE_HIDING_FILTER_DEVICE_EXTENSION)pDeviceObject->DeviceExtension;
        PFAST_IO_DISPATCH pFastIODispatch = NULL;        

        ASSERT(IS_FILE_HIDING_FILTER_OBJECT(pDeviceObject));
        ASSERT(NULL != pFilterDeviceExt->pNextLowerDevice);

        pFastIODispatch = pFilterDeviceExt->pNextLowerDevice->DriverObject->FastIoDispatch;

        // check Fast I/O handler validation on the next device
        if (VALID_FAST_IO_DISPATCH_HANDLER(pFastIODispatch, FastIoQueryBasicInfo))
        {
            // send Fast I/O to the next device
            return pFastIODispatch->FastIoQueryBasicInfo(pFileObject,
                                                         bWait,
                                                         pBuffer,
                                                         pIOStatus,
                                                         pFilterDeviceExt->pNextLowerDevice);
        }
    }

    return FALSE;
}

#pragma alloc_text(PAGE, FastIOQueryStandardInfo)

BOOLEAN FastIOQueryStandardInfo(IN PFILE_OBJECT pFileObject,
                                IN BOOLEAN bWait,
                                OUT PFILE_STANDARD_INFORMATION pBuffer,
                                OUT PIO_STATUS_BLOCK pIOStatus,
                                IN PDEVICE_OBJECT pDeviceObject)
{
    PAGED_CODE();

    // continue Fast I/O processing if attached to this device
    if (NULL != pDeviceObject->DeviceExtension)
    {
        PFILE_HIDING_FILTER_DEVICE_EXTENSION pFilterDeviceExt = (PFILE_HIDING_FILTER_DEVICE_EXTENSION)pDeviceObject->DeviceExtension;
        PFAST_IO_DISPATCH pFastIODispatch = NULL;        

        ASSERT(IS_FILE_HIDING_FILTER_OBJECT(pDeviceObject));
        ASSERT(NULL != pFilterDeviceExt->pNextLowerDevice);

        pFastIODispatch = pFilterDeviceExt->pNextLowerDevice->DriverObject->FastIoDispatch;

        // check Fast I/O handler validation on the next device
        if (VALID_FAST_IO_DISPATCH_HANDLER(pFastIODispatch, FastIoQueryStandardInfo))
        {
            // send Fast I/O to the next device
            return pFastIODispatch->FastIoQueryStandardInfo(pFileObject,
                                                            bWait,
                                                            pBuffer,
                                                            pIOStatus,
                                                            pFilterDeviceExt->pNextLowerDevice);
        }
    }

    return FALSE;
}

#pragma alloc_text(PAGE, FastIOLock)

BOOLEAN FastIOLock(IN PFILE_OBJECT pFileObject,
                   IN PLARGE_INTEGER pFileOffset,
                   IN PLARGE_INTEGER pLength,
                   IN PEPROCESS pProcessId,
                   IN ULONG uKey,
                   IN BOOLEAN bFailImmediately,
                   IN BOOLEAN bExclusiveLock,
                   OUT PIO_STATUS_BLOCK pIoStatus,
                   IN PDEVICE_OBJECT pDeviceObject)
{
    PAGED_CODE();

    // continue Fast I/O processing if attached to this device
    if (NULL != pDeviceObject->DeviceExtension)
    {
        PFILE_HIDING_FILTER_DEVICE_EXTENSION pFilterDeviceExt = (PFILE_HIDING_FILTER_DEVICE_EXTENSION)pDeviceObject->DeviceExtension;
        PFAST_IO_DISPATCH pFastIODispatch = NULL;        

        ASSERT(IS_FILE_HIDING_FILTER_OBJECT(pDeviceObject));
        ASSERT(NULL != pFilterDeviceExt->pNextLowerDevice);

        pFastIODispatch = pFilterDeviceExt->pNextLowerDevice->DriverObject->FastIoDispatch;

        // check Fast I/O handler validation on the next device
        if (VALID_FAST_IO_DISPATCH_HANDLER(pFastIODispatch, FastIoLock))
        {
            // send Fast I/O to the next device
            return pFastIODispatch->FastIoLock(pFileObject,
                                               pFileOffset,
                                               pLength,
                                               pProcessId,
                                               uKey,
                                               bFailImmediately,
                                               bExclusiveLock,
                                               pIoStatus,
                                               pFilterDeviceExt->pNextLowerDevice);
        }
    }

    return FALSE;
}

#pragma alloc_text(PAGE, FastIOUnlockSingle)

BOOLEAN FastIOUnlockSingle(IN PFILE_OBJECT pFileObject,
                           IN PLARGE_INTEGER pFileOffset,
                           IN PLARGE_INTEGER pLength,
                           IN PEPROCESS pProcessId,
                           IN ULONG uKey,
                           OUT PIO_STATUS_BLOCK pIoStatus,
                           IN PDEVICE_OBJECT pDeviceObject)
{
    PAGED_CODE();

    // continue Fast I/O processing if attached to this device
    if (NULL != pDeviceObject->DeviceExtension)
    {
        PFILE_HIDING_FILTER_DEVICE_EXTENSION pFilterDeviceExt = (PFILE_HIDING_FILTER_DEVICE_EXTENSION)pDeviceObject->DeviceExtension;
        PFAST_IO_DISPATCH pFastIODispatch = NULL;        

        ASSERT(IS_FILE_HIDING_FILTER_OBJECT(pDeviceObject));
        ASSERT(NULL != pFilterDeviceExt->pNextLowerDevice);

        pFastIODispatch = pFilterDeviceExt->pNextLowerDevice->DriverObject->FastIoDispatch;

        // check Fast I/O handler validation on the next device
        if (VALID_FAST_IO_DISPATCH_HANDLER(pFastIODispatch, FastIoUnlockSingle))
        {
            // send Fast I/O to the next device
            return pFastIODispatch->FastIoUnlockSingle(pFileObject,
                                                       pFileOffset,
                                                       pLength,
                                                       pProcessId,
                                                       uKey,
                                                       pIoStatus,
                                                       pFilterDeviceExt->pNextLowerDevice);
        }
    }

    return FALSE;
}

#pragma alloc_text(PAGE, FastIOUnlockAll)

BOOLEAN FastIOUnlockAll(IN PFILE_OBJECT pFileObject,
                        IN PEPROCESS pProcessId,
                        OUT PIO_STATUS_BLOCK pIoStatus,
                        IN PDEVICE_OBJECT pDeviceObject)
{
    PAGED_CODE();

    // continue Fast I/O processing if attached to this device
    if (NULL != pDeviceObject->DeviceExtension)
    {
        PFILE_HIDING_FILTER_DEVICE_EXTENSION pFilterDeviceExt = (PFILE_HIDING_FILTER_DEVICE_EXTENSION)pDeviceObject->DeviceExtension;
        PFAST_IO_DISPATCH pFastIODispatch = NULL;        

        ASSERT(IS_FILE_HIDING_FILTER_OBJECT(pDeviceObject));
        ASSERT(NULL != pFilterDeviceExt->pNextLowerDevice);

        pFastIODispatch = pFilterDeviceExt->pNextLowerDevice->DriverObject->FastIoDispatch;

        // check Fast I/O handler validation on the next device
        if (VALID_FAST_IO_DISPATCH_HANDLER(pFastIODispatch, FastIoUnlockAll))
        {
            // send Fast I/O to the next device
            return pFastIODispatch->FastIoUnlockAll(pFileObject,
                                                    pProcessId,
                                                    pIoStatus,
                                                    pFilterDeviceExt->pNextLowerDevice);
        }
    }

    return FALSE;
}

#pragma alloc_text(PAGE, FastIOUnlockAllByKey)

BOOLEAN FastIOUnlockAllByKey(IN PFILE_OBJECT pFileObject,
                             IN PVOID pProcessId,
                             IN ULONG uKey,
                             OUT PIO_STATUS_BLOCK pIoStatus,
                             IN PDEVICE_OBJECT pDeviceObject)
{
    PAGED_CODE();

    // continue Fast I/O processing if attached to this device
    if (NULL != pDeviceObject->DeviceExtension)
    {
        PFILE_HIDING_FILTER_DEVICE_EXTENSION pFilterDeviceExt = (PFILE_HIDING_FILTER_DEVICE_EXTENSION)pDeviceObject->DeviceExtension;
        PFAST_IO_DISPATCH pFastIODispatch = NULL;        

        ASSERT(IS_FILE_HIDING_FILTER_OBJECT(pDeviceObject));
        ASSERT(NULL != pFilterDeviceExt->pNextLowerDevice);

        pFastIODispatch = pFilterDeviceExt->pNextLowerDevice->DriverObject->FastIoDispatch;

        // check Fast I/O handler validation on the next device
        if (VALID_FAST_IO_DISPATCH_HANDLER(pFastIODispatch, FastIoUnlockAllByKey))
        {
            // send Fast I/O to the next device
            return pFastIODispatch->FastIoUnlockAllByKey(pFileObject,
                                                         pProcessId,
                                                         uKey,
                                                         pIoStatus,
                                                         pFilterDeviceExt->pNextLowerDevice);
        }
    }

    return FALSE;
}

#pragma alloc_text(PAGE, FastIODeviceControl)

BOOLEAN FastIODeviceControl(IN PFILE_OBJECT pFileObject,
                            IN BOOLEAN bWait,
                            IN OPTIONAL PVOID pInputBuffer,
                            IN ULONG uInputBufferLength,
                            OUT OPTIONAL PVOID pOutputBuffer,
                            IN ULONG uOutputBufferLength,
                            IN ULONG uIoControlCode,
                            OUT PIO_STATUS_BLOCK pIoStatus,
                            IN PDEVICE_OBJECT pDeviceObject)

{
    PAGED_CODE();

    // continue Fast I/O processing if attached to this device
    if (NULL != pDeviceObject->DeviceExtension)
    {
        PFILE_HIDING_FILTER_DEVICE_EXTENSION pFilterDeviceExt = (PFILE_HIDING_FILTER_DEVICE_EXTENSION)pDeviceObject->DeviceExtension;
        PFAST_IO_DISPATCH pFastIODispatch = NULL;        

        ASSERT(IS_FILE_HIDING_FILTER_OBJECT(pDeviceObject));
        ASSERT(NULL != pFilterDeviceExt->pNextLowerDevice);

        pFastIODispatch = pFilterDeviceExt->pNextLowerDevice->DriverObject->FastIoDispatch;

        // check Fast I/O handler validation on the next device
        if (VALID_FAST_IO_DISPATCH_HANDLER(pFastIODispatch, FastIoDeviceControl))
        {
            // send Fast I/O to the next device
            return pFastIODispatch->FastIoDeviceControl(pFileObject,
                                                        bWait,
                                                        pInputBuffer,    
                                                        uInputBufferLength,
                                                        pOutputBuffer, 
                                                        uOutputBufferLength,
                                                        uIoControlCode,
                                                        pIoStatus,
                                                        pFilterDeviceExt->pNextLowerDevice);
        }
    }

    return FALSE;
}

#pragma alloc_text(PAGE, FastIODetachDevice)

VOID FastIODetachDevice(IN PDEVICE_OBJECT pSourceDevice,
                        IN PDEVICE_OBJECT pTargetDevice)
{
    ASSERT(IS_FILE_HIDING_FILTER_OBJECT (pSourceDevice));

    IoDetachDevice(pTargetDevice);
    IoDeleteDevice(pSourceDevice);
}

#pragma alloc_text(PAGE, FastIOQueryNetworkOpenInfo)

BOOLEAN FastIOQueryNetworkOpenInfo(IN PFILE_OBJECT pFileObject,
                                   IN BOOLEAN bWait,
                                   OUT PFILE_NETWORK_OPEN_INFORMATION pBuffer,
                                   OUT PIO_STATUS_BLOCK pIoStatus,
                                   IN PDEVICE_OBJECT pDeviceObject)
{
    PAGED_CODE();

    // continue Fast I/O processing if attached to this device
    if (NULL != pDeviceObject->DeviceExtension)
    {
        PFILE_HIDING_FILTER_DEVICE_EXTENSION pFilterDeviceExt = (PFILE_HIDING_FILTER_DEVICE_EXTENSION)pDeviceObject->DeviceExtension;
        PFAST_IO_DISPATCH pFastIODispatch = NULL;        

        ASSERT(IS_FILE_HIDING_FILTER_OBJECT(pDeviceObject));
        ASSERT(NULL != pFilterDeviceExt->pNextLowerDevice);

        pFastIODispatch = pFilterDeviceExt->pNextLowerDevice->DriverObject->FastIoDispatch;

        // check Fast I/O handler validation on the next device
        if (VALID_FAST_IO_DISPATCH_HANDLER(pFastIODispatch, FastIoQueryNetworkOpenInfo))
        {
            // send Fast I/O to the next device
            return pFastIODispatch->FastIoQueryNetworkOpenInfo(pFileObject,
                                                               bWait,
                                                               pBuffer,
                                                               pIoStatus,
                                                               pFilterDeviceExt->pNextLowerDevice);
        }
    }

    return FALSE;
}

#pragma alloc_text(PAGE, MdlRead)

BOOLEAN MdlRead(IN PFILE_OBJECT pFileObject,
                IN PLARGE_INTEGER pFileOffset,
                IN ULONG ulLength,
                IN ULONG ulLockKey,
                OUT PMDL* pMdlChain,
                OUT PIO_STATUS_BLOCK pIoStatus,
                IN PDEVICE_OBJECT pDeviceObject)
{
    PAGED_CODE();

    // continue Fast I/O processing if attached to this device
    if (NULL != pDeviceObject->DeviceExtension)
    {
        PFILE_HIDING_FILTER_DEVICE_EXTENSION pFilterDeviceExt = (PFILE_HIDING_FILTER_DEVICE_EXTENSION)pDeviceObject->DeviceExtension;
        PFAST_IO_DISPATCH pFastIODispatch = NULL;        

        ASSERT(IS_FILE_HIDING_FILTER_OBJECT(pDeviceObject));
        ASSERT(NULL != pFilterDeviceExt->pNextLowerDevice);

        pFastIODispatch = pFilterDeviceExt->pNextLowerDevice->DriverObject->FastIoDispatch;

        // check Fast I/O handler validation on the next device
        if (VALID_FAST_IO_DISPATCH_HANDLER(pFastIODispatch, MdlRead))
        {
            // send Fast I/O to the next device
            return pFastIODispatch->MdlRead(pFileObject,
                                            pFileOffset,
                                            ulLength,
                                            ulLockKey,
                                            pMdlChain,
                                            pIoStatus,
                                            pFilterDeviceExt->pNextLowerDevice);
        }
    }

    return FALSE;
}

#pragma alloc_text(PAGE, MdlReadComplete)

BOOLEAN MdlReadComplete(IN PFILE_OBJECT pFileObject,
                        IN PMDL pMdlChain,
                        IN PDEVICE_OBJECT pDeviceObject)
{
    PAGED_CODE();

    // continue Fast I/O processing if attached to this device
    if (NULL != pDeviceObject->DeviceExtension)
    {
        PFILE_HIDING_FILTER_DEVICE_EXTENSION pFilterDeviceExt = (PFILE_HIDING_FILTER_DEVICE_EXTENSION)pDeviceObject->DeviceExtension;
        PFAST_IO_DISPATCH pFastIODispatch = NULL;        

        ASSERT(IS_FILE_HIDING_FILTER_OBJECT(pDeviceObject));
        ASSERT(NULL != pFilterDeviceExt->pNextLowerDevice);

        pFastIODispatch = pFilterDeviceExt->pNextLowerDevice->DriverObject->FastIoDispatch;

        // check Fast I/O handler validation on the next device
        if (VALID_FAST_IO_DISPATCH_HANDLER(pFastIODispatch, MdlReadComplete))
        {
            // send Fast I/O to the next device
            return pFastIODispatch->MdlReadComplete(pFileObject,
                                                    pMdlChain,
                                                    pFilterDeviceExt->pNextLowerDevice);
        }
    }

    return FALSE;
}

#pragma alloc_text(PAGE, PrepareMdlWrite)

BOOLEAN PrepareMdlWrite(IN PFILE_OBJECT pFileObject,
                        IN PLARGE_INTEGER pFileOffset,
                        IN ULONG ulLength,
                        IN ULONG ulLockKey,
                        OUT PMDL* pMdlChain,
                        OUT PIO_STATUS_BLOCK pIoStatus,
                        IN PDEVICE_OBJECT pDeviceObject)
{
    PAGED_CODE();

    // continue Fast I/O processing if attached to this device
    if (NULL != pDeviceObject->DeviceExtension)
    {
        PFILE_HIDING_FILTER_DEVICE_EXTENSION pFilterDeviceExt = (PFILE_HIDING_FILTER_DEVICE_EXTENSION)pDeviceObject->DeviceExtension;
        PFAST_IO_DISPATCH pFastIODispatch = NULL;        

        ASSERT(IS_FILE_HIDING_FILTER_OBJECT(pDeviceObject));
        ASSERT(NULL != pFilterDeviceExt->pNextLowerDevice);

        pFastIODispatch = pFilterDeviceExt->pNextLowerDevice->DriverObject->FastIoDispatch;

        // check Fast I/O handler validation on the next device
        if (VALID_FAST_IO_DISPATCH_HANDLER(pFastIODispatch, PrepareMdlWrite))
        {
            // send Fast I/O to the next device
            return pFastIODispatch->PrepareMdlWrite(pFileObject,
                                                    pFileOffset,
                                                    ulLength,
                                                    ulLockKey,
                                                    pMdlChain,
                                                    pIoStatus,
                                                    pFilterDeviceExt->pNextLowerDevice);
        }
    }

    return FALSE;
}

#pragma alloc_text(PAGE, MdlWriteComplete)

BOOLEAN MdlWriteComplete(IN PFILE_OBJECT pFileObject,
                         IN PLARGE_INTEGER pFileOffset,
                         IN PMDL pMdlChain,
                         IN PDEVICE_OBJECT pDeviceObject)
{
    PAGED_CODE();

    // continue Fast I/O processing if attached to this device
    if (NULL != pDeviceObject->DeviceExtension)
    {
        PFILE_HIDING_FILTER_DEVICE_EXTENSION pFilterDeviceExt = (PFILE_HIDING_FILTER_DEVICE_EXTENSION)pDeviceObject->DeviceExtension;
        PFAST_IO_DISPATCH pFastIODispatch = NULL;        

        ASSERT(IS_FILE_HIDING_FILTER_OBJECT(pDeviceObject));
        ASSERT(NULL != pFilterDeviceExt->pNextLowerDevice);

        pFastIODispatch = pFilterDeviceExt->pNextLowerDevice->DriverObject->FastIoDispatch;

        // check Fast I/O handler validation on the next device
        if (VALID_FAST_IO_DISPATCH_HANDLER(pFastIODispatch, MdlWriteComplete))
        {
            // send Fast I/O to the next device
            return pFastIODispatch->MdlWriteComplete(pFileObject,
                                                     pFileOffset,
                                                     pMdlChain,
                                                     pFilterDeviceExt->pNextLowerDevice);
        }
    }

    return FALSE;
}

#pragma alloc_text(PAGE, FastIoReadCompressed)

BOOLEAN FastIoReadCompressed(IN PFILE_OBJECT pFileObject,
                             IN PLARGE_INTEGER pFileOffset,
                             IN ULONG ulLength,
                             IN ULONG ulLockKey,
                             OUT PVOID pBuffer,
                             OUT PMDL* pMdlChain,
                             OUT PIO_STATUS_BLOCK pIoStatus,
                             OUT PCOMPRESSED_DATA_INFO pCompressedDataInfo,
                             IN ULONG ulCompressedDataInfoLength,
                             IN PDEVICE_OBJECT pDeviceObject)
{
    PAGED_CODE();

    // continue Fast I/O processing if attached to this device
    if (NULL != pDeviceObject->DeviceExtension)
    {
        PFILE_HIDING_FILTER_DEVICE_EXTENSION pFilterDeviceExt = (PFILE_HIDING_FILTER_DEVICE_EXTENSION)pDeviceObject->DeviceExtension;
        PFAST_IO_DISPATCH pFastIODispatch = NULL;        

        ASSERT(IS_FILE_HIDING_FILTER_OBJECT(pDeviceObject));
        ASSERT(NULL != pFilterDeviceExt->pNextLowerDevice);

        pFastIODispatch = pFilterDeviceExt->pNextLowerDevice->DriverObject->FastIoDispatch;

        // check Fast I/O handler validation on the next device
        if (VALID_FAST_IO_DISPATCH_HANDLER(pFastIODispatch, FastIoReadCompressed))
        {
            // send Fast I/O to the next device
            return pFastIODispatch->FastIoReadCompressed(pFileObject,
                                                         pFileOffset,
                                                         ulLength,
                                                         ulLockKey,
                                                         pBuffer,
                                                         pMdlChain,
                                                         pIoStatus,
                                                         pCompressedDataInfo,
                                                         ulCompressedDataInfoLength,
                                                         pFilterDeviceExt->pNextLowerDevice);
        }
    }

    return FALSE;
}

#pragma alloc_text(PAGE, FastIoWriteCompressed)

BOOLEAN FastIoWriteCompressed(IN PFILE_OBJECT pFileObject,
                              IN PLARGE_INTEGER pFileOffset,
                              IN ULONG ulLength,
                              IN ULONG ulLockKey,
                              IN PVOID pBuffer,
                              OUT PMDL* pMdlChain,
                              OUT PIO_STATUS_BLOCK pIoStatus,
                              IN PCOMPRESSED_DATA_INFO pCompressedDataInfo,
                              IN ULONG ulCompressedDataInfoLength,
                              IN PDEVICE_OBJECT pDeviceObject)
{
    PAGED_CODE();

    // continue Fast I/O processing if attached to this device
    if (NULL != pDeviceObject->DeviceExtension)
    {
        PFILE_HIDING_FILTER_DEVICE_EXTENSION pFilterDeviceExt = (PFILE_HIDING_FILTER_DEVICE_EXTENSION)pDeviceObject->DeviceExtension;
        PFAST_IO_DISPATCH pFastIODispatch = NULL;        

        ASSERT(IS_FILE_HIDING_FILTER_OBJECT(pDeviceObject));
        ASSERT(NULL != pFilterDeviceExt->pNextLowerDevice);

        pFastIODispatch = pFilterDeviceExt->pNextLowerDevice->DriverObject->FastIoDispatch;

        // check Fast I/O handler validation on the next device
        if (VALID_FAST_IO_DISPATCH_HANDLER(pFastIODispatch, FastIoWriteCompressed))
        {
            // send Fast I/O to the next device
            return pFastIODispatch->FastIoWriteCompressed(pFileObject,
                                                          pFileOffset,
                                                          ulLength,
                                                          ulLockKey,
                                                          pBuffer,
                                                          pMdlChain,
                                                          pIoStatus,
                                                          pCompressedDataInfo,
                                                          ulCompressedDataInfoLength,
                                                          pFilterDeviceExt->pNextLowerDevice);
        }
    }

    return FALSE;
}

#pragma alloc_text(PAGE, MdlReadCompleteCompressed)

BOOLEAN MdlReadCompleteCompressed(IN PFILE_OBJECT pFileObject,
                                  IN PMDL pMdlChain,
                                  IN PDEVICE_OBJECT pDeviceObject)
{
    PAGED_CODE();

    // continue Fast I/O processing if attached to this device
    if (NULL != pDeviceObject->DeviceExtension)
    {
        PFILE_HIDING_FILTER_DEVICE_EXTENSION pFilterDeviceExt = (PFILE_HIDING_FILTER_DEVICE_EXTENSION)pDeviceObject->DeviceExtension;
        PFAST_IO_DISPATCH pFastIODispatch = NULL;        

        ASSERT(IS_FILE_HIDING_FILTER_OBJECT(pDeviceObject));
        ASSERT(NULL != pFilterDeviceExt->pNextLowerDevice);

        pFastIODispatch = pFilterDeviceExt->pNextLowerDevice->DriverObject->FastIoDispatch;

        // check Fast I/O handler validation on the next device
        if (VALID_FAST_IO_DISPATCH_HANDLER(pFastIODispatch, MdlReadCompleteCompressed))
        {
            // send Fast I/O to the next device
            return pFastIODispatch->MdlReadCompleteCompressed(pFileObject,
                                                              pMdlChain,
                                                              pFilterDeviceExt->pNextLowerDevice);
        }
    }

    return FALSE;
}

#pragma alloc_text(PAGE, MdlWriteCompleteCompressed)

BOOLEAN MdlWriteCompleteCompressed(IN PFILE_OBJECT pFileObject,
                                   IN PLARGE_INTEGER pFileOffset,
                                   IN PMDL pMdlChain,
                                   IN PDEVICE_OBJECT pDeviceObject)
{
    PAGED_CODE();

    // continue Fast I/O processing if attached to this device
    if (NULL != pDeviceObject->DeviceExtension)
    {
        PFILE_HIDING_FILTER_DEVICE_EXTENSION pFilterDeviceExt = (PFILE_HIDING_FILTER_DEVICE_EXTENSION)pDeviceObject->DeviceExtension;
        PFAST_IO_DISPATCH pFastIODispatch = NULL;        

        ASSERT(IS_FILE_HIDING_FILTER_OBJECT(pDeviceObject));
        ASSERT(NULL != pFilterDeviceExt->pNextLowerDevice);

        pFastIODispatch = pFilterDeviceExt->pNextLowerDevice->DriverObject->FastIoDispatch;

        // check Fast I/O handler validation on the next device
        if (VALID_FAST_IO_DISPATCH_HANDLER(pFastIODispatch, MdlWriteCompleteCompressed))
        {
            // send Fast I/O to the next device
            return pFastIODispatch->MdlWriteCompleteCompressed(pFileObject,
                                                               pFileOffset,
                                                               pMdlChain,
                                                               pFilterDeviceExt->pNextLowerDevice);
        }
    }

    return FALSE;
}

#pragma alloc_text(PAGE, FastIoQueryOpen)

BOOLEAN FastIoQueryOpen(IN OUT PIRP pIRP,
                        OUT PFILE_NETWORK_OPEN_INFORMATION pNetworkInformation,
                        IN PDEVICE_OBJECT pDeviceObject)
{
    PAGED_CODE();

    // continue Fast I/O processing if attached to this device
    if (NULL != pDeviceObject->DeviceExtension)
    {
        PFILE_HIDING_FILTER_DEVICE_EXTENSION pFilterDeviceExt = (PFILE_HIDING_FILTER_DEVICE_EXTENSION)pDeviceObject->DeviceExtension;
        PFAST_IO_DISPATCH pFastIODispatch = NULL;        

        ASSERT(IS_FILE_HIDING_FILTER_OBJECT(pDeviceObject));
        ASSERT(NULL != pFilterDeviceExt->pNextLowerDevice);

        pFastIODispatch = pFilterDeviceExt->pNextLowerDevice->DriverObject->FastIoDispatch;

        // check Fast I/O handler validation on the next device
        if (VALID_FAST_IO_DISPATCH_HANDLER(pFastIODispatch, MdlWriteCompleteCompressed))
        {
            // send Fast I/O to the next device
            return pFastIODispatch->FastIoQueryOpen(pIRP,
                                                    pNetworkInformation,
                                                    pFilterDeviceExt->pNextLowerDevice);
        }
    }

    return FALSE;
}